home *** CD-ROM | disk | FTP | other *** search
- /*
- ***** TandbergConf
- *
- * A utility to configure Tandberg TDC3600 SCSI Tape drives.
- *
- * - Turn on/off Auto retension
- * - Settings can be permanant or will reset after a re-boot/power on
- *
- * Note:
- * This code was hacked from an excellent program called SCSIutil,
- * written by Gary Duncan (gduncan@philips.oz.au), modified by
- * Heiko Rath (hr@brewhr.swb.de)
- *
- * Information on how to program the TDC3600 was provided by Goncal
- * Badenes (badenes@imec.be)
- *
- * Program returns:
- * 1 - init didn't work (maybe allocmem failed, etc.)
- * 2 - wrong parameter count
- * 3 - wrong parameter
- *
- */
-
- #define VERSION "1.0"
-
- /*
- **** Includes
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #include <exec/types.h>
- #include <exec/io.h>
- #include <exec/execbase.h>
- #include <exec/nodes.h>
- #include <exec/memory.h>
- #include <devices/trackdisk.h>
- #include <devices/scsidisk.h>
- #include <dos/rdargs.h>
- #include <libraries/dos.h>
- #ifdef __SASC
- #include <proto/all.h>
- #endif
- #include "scsi_priv.h"
-
- /*
- **** Global variables
- */
- UBYTE *scsi_data = NULL;
-
- UBYTE *dev = "";
-
- int scsi_id = -1; /* ID of the SCSI device to send commands to */
- UBYTE *pname;
- UBYTE buffer[LINE_BUF];
- int secno = -1;
-
- MSGPORT *mp_ptr;
- IOSTDREQ *io_ptr;
- SCSICMD scsi_cmd;
- UBYTE *scsi_sense;
- UBYTE scsi_status;
-
-
- /*
- **** Function descr.
- */
- int breakcheck (void);
- int DoScsiCmd (UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags, BOOLEAN);
- UBYTE *err_str (int err);
- void exit (int status);
- UBYTE *GetDevName (char *grep);
- BOOLEAN init (void);
- void inquiry (void);
- void mode_sense (BOOLEAN parsed, UBYTE control, UBYTE page);
- void rawhexasciioutput (UBYTE *p, UWORD numbytes, UBYTE leadspace);
- UBYTE *sense_errs (int req, int err);
- void usage (void);
- void write_mode(BOOLEAN, UBYTE *, int);
- void parse_mode(void);
-
- #ifdef __SASC
- void __regargs __chkabort (void);
- #endif /* __SASC */
- #define RAW ra_array[2]
- #define RETENSION ra_array[3]
- #define AUTOLOAD ra_array[4]
- #define SAVE ra_array[5]
- #define QUIET ra_array[6]
-
- /*********************************************************************
- *
- * main
- *
- *
- */
-
- int
- main (int argc, char **argv)
- {
- long ra_array[7] = {0,0,0,0,0,0,0};
- struct RDArgs *ra;
- static UBYTE cmd_data[24];
- int returnvalue = 0;
-
- if (argc == 1)
- {
- usage ();
- exit (1);
- }
-
- ra = ReadArgs("UNIT/N/R,DEVICE/K,RAW/S,RETENSION/S,AUTOLOAD/S,SAVE/S,QUIET/S", ra_array, NULL);
- if (!ra) {
- usage();
- return 3;
- }
-
- /*
- * see if a SCSI.device specified
- */
- if (ra_array[1])
- dev = (char *)ra_array[1];
- else if ((dev = GetDevName (SCSI_STRING)) == NULL)
- {
- fprintf (stderr, "Error : no *scsi*.device in device list\n");
- returnvalue = 1;
- goto error;
- }
- pname = argv[0];
-
- scsi_id = *(long *)ra_array[0];
- /*
- * now set up structures etc for SCSI xfer
- */
- if (init () == FALSE)
- {
- returnvalue = 1;
- goto error;
- }
-
- mode_sense(FALSE,0,0);
- inquiry();
- if (strncmp(&scsi_data[8], "TANDBERG", 8)) {
- fprintf(stderr, "Device not a Tandberg drive!\n");
- returnvalue = 2;
- goto error;
- }
-
- /*
- * read the mode sense data. We do this twice due to the fact that for some
- * reason, the first one fails.
- */
-
- mode_sense(FALSE,0,0);
- mode_sense(TRUE,0,0);
-
- if (!QUIET) {
- printf("Current Configuration:\n");
- if (RAW)
- rawhexasciioutput(scsi_data, scsi_data[0]+1, 0);
- else
- parse_mode();
- }
- if (RETENSION | AUTOLOAD) {
- memcpy(cmd_data, scsi_data,24);
- cmd_data[0] = 0x00;
- cmd_data[1] = 0x00;
-
- if (RETENSION)
- cmd_data[22] = 0x01;
- if (AUTOLOAD)
- cmd_data[22] = 0x00;
-
- if(SAVE)
- write_mode(TRUE, cmd_data, 24);
- else
- write_mode(FALSE, cmd_data, 24);
-
- if (!QUIET) {
- mode_sense(TRUE,0,0);
- printf("New Configuration:\n");
- if (RAW)
- rawhexasciioutput(scsi_data, scsi_data[0]+1, 0);
- else
- parse_mode();
- }
- }
-
- error:
-
- FreeArgs(ra);
-
- if (io_ptr)
- {
- CloseDevice ((struct IORequest *) io_ptr);
- DeleteStdIO (io_ptr);
- }
-
- if (mp_ptr)
- DeletePort (mp_ptr);
-
- if (scsi_sense)
- FreeMem (scsi_sense, SENSE_LEN);
-
- if (scsi_data)
- FreeMem (scsi_data, MAX_DATA_LEN);
-
- exit (returnvalue);
- }
-
- /*********************************************************************
- * DWL
- * function to write mode select info to a Tandberg drive
- */
-
- void
- write_mode(BOOLEAN permanant, UBYTE *cmd_data, int cmd_data_len)
- {
- static SCSICMD6 command =
- {
- 0x15,/* 0x15 MODE SELECT scsi command */
- 0, /* LUN | rsrvd. | DBD | rsrvd. */
- 0, /* PC | Page Code */
- 0, /* rsrvd. */
- 0x00, /* allocation length */
- 0x00 /* control */
- };
- /* static __chip UBYTE cmd_data[24] = {
- 0,0,0x10,8,0x10,0,0,0,0,0,2,0,0,2,2,0x78,0,0,8,0,0,0,0,0x64
- }; */
-
-
- int err;
-
- if (permanant)
- command.control = 0x40;
- else
- command.control = 0x00;
-
- command.b4 = cmd_data_len;
-
- if ((err = DoScsiCmd ((UBYTE *) cmd_data, cmd_data_len,
- (UBYTE *) &command, sizeof (command),
- (SCSIF_WRITE | SCSIF_AUTOSENSE), TRUE)) != 0)
- {
- fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
- }
- }
-
- /*********************************************************************
- *
- * Initialization function
- *
- */
- BOOLEAN
- init (void)
- {
-
- if ((scsi_data = (UBYTE *) AllocMem (MAX_DATA_LEN, MEMF_CHIP | MEMF_CLEAR)) == NULL)
- {
- fprintf (stderr, "AllocMem(0) Fail\n");
- return FALSE;
- }
-
- if ((scsi_sense = (UBYTE *) AllocMem (SENSE_LEN, MEMF_CHIP || MEMF_CLEAR)) == NULL)
- {
- fprintf (stderr, "AllocMem (scsi_sense) Fail\n");
- return FALSE;
- }
- if ((mp_ptr = (MSGPORT *) CreatePort (NULL, 0)) == NULL)
- {
- fprintf (stderr, "CreatePort (mp_ptr) Fail\n");
- return FALSE;
- }
- if ((io_ptr = (IOSTDREQ *) CreateStdIO (mp_ptr)) == NULL)
- {
- fprintf (stderr, "CreateStdIO (io_ptr) Fail\n");
- return FALSE;
- }
- if (OpenDevice (dev, scsi_id, (struct IORequest *) io_ptr, 0) != 0)
- {
- fprintf (stderr,
- "Error %d while opening SCSI dev \"%s\", unit (%d)\n",
- io_ptr->io_Error, dev, scsi_id);
- return FALSE;
- }
-
- return TRUE;
- }
-
- /*********************************************************************
- *
- * function to read parameter pages from a device
- */
-
- void
- mode_sense (BOOLEAN error_chk, UBYTE control, UBYTE page)
- {
- static SCSICMD6 command =
- {
- SCSI_CMD_MSE, /* 0x1a MODE SENSE scsi command */
- PAD, /* LUN | rsrvd. | DBD | rsrvd. */
- 0, /* PC | Page Code */
- PAD, /* rsrvd. */
- 0, /* allocation length */
- PAD /* control */
- };
-
- int err;
-
- command.b2 = (control<<6) | page;
- command.b4 = MAX_DATA_LEN;
-
- err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
- (UBYTE *) &command, sizeof (command),
- (SCSIF_READ | SCSIF_AUTOSENSE), error_chk);
- if (err != 0) {
- if (error_chk)
- fprintf (stderr, "Error : err=%ld , %s \n", err, sense_errs (0, err));
- }
- }
-
- /*********************************************************************
- *
- * subroutine used to printout raw hex data bytes with the
- * corresponding ASCII values and an index
- *
- */
- void
- rawhexasciioutput (UBYTE *p, UWORD numbytes, UBYTE leadspace)
- {
- UWORD i, j;
- UBYTE *boff, *aoff;
- int xxxlen = strlen (" xx"); /* byte */
-
- buffer[5+leadspace] = '=';
-
- for (i = 0; i < numbytes; i += BYTES_PER_LINE)
- {
- memset (buffer, ' ', sizeof (buffer)); /* put spaces in buffer */
- boff = &buffer[7+leadspace];
- aoff = boff + (xxxlen * BYTES_PER_LINE) + 1;
-
- sprintf (buffer+leadspace, "%04X = ", i); /* add offset */
-
- for (j = 0; (j < BYTES_PER_LINE && (i+j) < numbytes); j++, boff += xxxlen, p++, aoff++)
- {
- sprintf (boff, " %02X", *p);
- *aoff = (isascii (*p) && isprint (*p)) ? *p : '.';
- }
-
- buffer[strlen (buffer)] = ' ';
- *++aoff = '\n';
- *++aoff = '\0';
- printf ("%s", buffer);
- }
- }
-
- /*********************************************************************
- *
- * function to make an inquiry
- *
- */
-
- void
- inquiry ()
- {
- static SCSICMD6 command =
- {
- SCSI_CMD_INQ, /* 0x12 INQUIRY */
- PAD, /* Bits 7-5 Logical Unit Number | Bits 4-1 Reserved | Bit 0 EVPD */
- PAD, /* Page Code */
- PAD, /* Reserved */
- 0, /* Allocation length */
- PAD /* Control */
- };
-
- int err;
-
- command.b4 = MAX_DATA_LEN; /* Allocation length = max. data length */
-
- if ((err = DoScsiCmd ((UBYTE *) scsi_data, MAX_DATA_LEN,
- (UBYTE *) & command, sizeof (command),
- (SCSIF_READ | SCSIF_AUTOSENSE), TRUE)) != 0)
- fprintf (stderr, "Inquiry Error : err=%ld , %s\n", err, sense_errs (0, err));
- }
-
- /*********************************************************************
- *
- * searches DeviceList for a device name with a given string in it.
- * - if found returns with a pointer to it, else NULL
- */
-
- extern struct ExecBase *SysBase;
-
- UBYTE *
- GetDevName (char *grep)
- {
- LIST *lh = (LIST *) SysBase->DeviceList.lh_Head;
- NODE *ln;
-
- for (ln = lh->lh_Head; ln->ln_Succ; ln = ln->ln_Succ)
- {
- UBYTE *p = ln->ln_Name;
-
- while (*p != '.')
- {
- if (strncmp (p, grep, 4) == 0)
- {
- return (ln->ln_Name);
- }
- ++p;
- }
- }
-
- return (NULL); /* not found */
- }
-
- /*********************************************************************
- *
- * Break (^C) function
- *
- */
-
- int
- breakcheck (void)
- {
- int zz = SetSignal (0L, SIGBREAKF_CTRL_C) & SIGBREAKF_CTRL_C;
- if (zz)
- {
- printf ("\n***BREAK: ^C\n");
- }
- return (zz);
- }
-
- #ifdef __SASC
- /*********************************************************************
- *
- * tell SAS to turn of CTRL-C checking
- */
- void __regargs
- __chkabort (void)
- {
- }
-
- #endif
-
- /*********************************************************************
- *
- * function to use a scsi command
- *
- */
- int
- DoScsiCmd (UBYTE * data, int datasize, UBYTE * cmd, int cmdsize, UBYTE flags, BOOLEAN error_report)
- {
- int i;
-
- io_ptr->io_Length = sizeof (SCSICMD);
- io_ptr->io_Data = (APTR) & scsi_cmd;
- io_ptr->io_Command = HD_SCSICMD;
-
- scsi_cmd.scsi_Data = (APTR) data;
- scsi_cmd.scsi_Length = datasize;
- scsi_cmd.scsi_SenseActual = 0;
- scsi_cmd.scsi_SenseData = scsi_sense;
- scsi_cmd.scsi_SenseLength = SENSE_LEN;
- scsi_cmd.scsi_Command = cmd;
- scsi_cmd.scsi_CmdLength = cmdsize;
- scsi_cmd.scsi_Flags = flags;
-
- (void) DoIO ((struct IORequest *) io_ptr);
-
- if (scsi_cmd.scsi_SenseActual && error_report)
- {
- fprintf (stderr, "SENSE_DATA:");
- for (i = 0; i < scsi_cmd.scsi_SenseActual; i++)
- {
- fprintf (stderr, " %02x", scsi_cmd.scsi_SenseData[i]);
- }
- fprintf (stderr, "\n");
- }
- return (io_ptr->io_Error);
- }
-
- /*********************************************************************
- *
- * function to return an error string
- *
- *
- */
-
- UBYTE *
- err_str (int err)
- {
-
- static UBYTE *errors[] =
- {
- " cannot issue SCSI command to self ",
- " DMA error ",
- " illegal or unexpected SCSI phase ",
- " SCSI parity error ",
- " Select timed out ",
- " status and/or sense error "
- };
-
- err -= 40;
-
- if ((err < 0) || (err > 5))
- return ("Error out-of-range");
- else
- return (errors[err]);
- }
-
- /*********************************************************************
- *
- * usage function
- *
- *
- */
-
- void
- usage (void)
- {
- static char *zz[] =
- {
- "Usage: TandbergConf [UNIT] unit [DEVICE devname] [RAW] [RETENSION | AUTOLOAD] [SAVE] [QUIET]\n",
- " where:\n",
- " unit = (Required) SCSI unit number of Tandberg tape drive\n",
- " devname = SCSI device name (Default scsi.device)\n",
- " RAW = Show configuration in hex mode(Default, text mode)\n",
- " RETENSION = Retension tape when inserted or on reset\n",
- " AUTOLOAD = Position tape at load point when inserted or on reset\n",
- " SAVE = Make changes permanant (Default, temporary)\n",
- " QUIET = Do not print configuration(s)\n",
- "" /* TERM */
- };
-
- int j = 0;
-
- fprintf (stderr, "TandbergConf V%s [%s : %s] - written by Dave Lowrey\n",
- VERSION, __DATE__, __TIME__, pname);
-
- while (*zz[j++])
- fprintf (stderr, "%s", zz[j - 1]);
- }
-
- /*********************************************************************
- *
- * sense_errs function ; prints sense errors
- *
- *
- */
-
- UBYTE *
- sense_errs (int req, int err)
- {
- typedef struct
- {
- BYTE code;
- BYTE sense;
- UBYTE *ptr;
- } S_ERRS;
-
- /*
- * only the likely, interesting ones filled in, e.g media errors
- */
- static S_ERRS x[] =
- {
- 0x00, 0x00, "No error",
- 0x01, 0x04, "?",
- 0x02, 0x04, "?",
- 0x03, 0x04, "?",
- 0x04, 0x02, "?",
- 0x06, 0x04, "?",
- 0x09, 0x04, "?",
- 0x10, 0x03, "?",
- 0x10, 0x04, "?",
- 0x11, 0x03, "?",
- 0x12, 0x03, "?",
- 0x13, 0x03, "?",
- 0x14, 0x03, "?",
- 0x15, 0x04, "Seek error ",
- 0x17, 0x01, "?",
- 0x18, 0x01, "?",
- 0x19, 0x03, "?",
- 0x1A, 0x05, "?",
- 0x20, 0x05, "Invalid command op code",
- 0x21, 0x05, "Illegal sector address",
- 0x24, 0x05, "?",
- 0x25, 0x05, "Invalid LUN",
- 0x26, 0x05, "Invalid field in parameter list",
- 0x29, 0x06, "?",
- 0x2A, 0x06, "?",
- 0x31, 0x03, "?",
- 0x32, 0x01, "?",
- 0x32, 0x03, "?",
- 0x40, 0x04, "?",
- 0x41, 0x04, "?",
- 0x42, 0x04, "Power-on diagnostic failure",
- 0x43, 0x04, "?",
- 0x45, 0x04, "Select / reselect failure ",
- 0x47, 0x04, "SCSI Interface Parity Error",
- 0x48, 0x0B, "?",
- 0x49, 0x0B, "Illegal message drive can't support",
- -1, -1, "ILLEGAL sense!!"
- };
-
- int j = 0;
- UBYTE *p;
- char sense;
- char code;
-
- /*
- * verify that sense data looks valid
- */
- if (((scsi_cmd.scsi_Status & 2) == 0) ||
- (scsi_cmd.scsi_SenseActual < OFFS_KEY))
- {
- return ("");
- }
- sense = scsi_cmd.scsi_SenseData[OFFS_KEY] & 0xF;
- code = scsi_cmd.scsi_SenseData[OFFS_CODE];
-
- do
- {
- p = x[j].ptr;
- if ((x[j].code == code) && (x[j].sense == sense))
- break;
- } while (x[j++].code != -1);
-
- return (p);
- }
-
- void parse_mode()
- {
-
- /* printf("Density: ");
- if(scsi_data[4] == 0x00)
- printf("Default\n");
- else if (scsi_data[4] == 0x0f)
- printf("QIC-120\n");
- else if (scsi_data[4] == 0x10)
- printf("QIC-150\n");
- else
- printf("Unknown\n");
- */
- printf("Load Function: ");
- if (scsi_data[22] == 0x00)
- printf("AUTOLOAD\n");
- else if (scsi_data[22] == 0x01)
- printf("RETENSION\n");
- else
- printf("Unknown\n");
- }
-